package fr.umlv.ig.extraWindows;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.SpinnerNumberModel;

import fr.umlv.ig.event.StationEvent;
import fr.umlv.ig.event.TrainEvent;
import fr.umlv.ig.listener.StationAdapter;
import fr.umlv.ig.listener.TrainListener;
import fr.umlv.ig.model.Line;
import fr.umlv.ig.model.MetroModelImpl;
import fr.umlv.ig.model.Station;


/**
 * Windows to configure the application.
 */
@SuppressWarnings("serial")
public class ConfigurationWindow extends ExtraWindow {

	/**
	 * MetroModelImpl to configure
	 */
	private final MetroModelImpl model;
	
	/**
	 * Tabbedpane used.
	 */
	private final JTabbedPane tabpane = new JTabbedPane(JTabbedPane.TOP);
	
	/**panel used in the window*/
	private final JPanel p = new JPanel();
	
	/**map to associate everyStation by a JSpinner*/
	private final Map<Station, JSpinner> mapStationSpinner;
	
	/**Map to associate every Line by a JSpinner.*/
	private final Map<Line, JSpinner> mapLineSpinner;

	/**
	 * Initialize a windows to configure and {@link MetroModelImpl} and start
	 * use program.
	 * @param owner owner's window.
	 * @param title title of the ExtraWindow.
	 * @param model model which will be configure.
	 */
	public ConfigurationWindow(JFrame owner, String title,MetroModelImpl model) {
		super(owner, title, true, 700, 550);
		mapStationSpinner = new HashMap<Station, JSpinner>();
		mapLineSpinner = new HashMap<Line, JSpinner>();
		this.model = model;
		init();
		dispose();
	}

	/** Create a waiting time panel
	 * @param nbLine the number of line
	 * @param begin
	 * @param end
	 * @return
	 */
	private JPanel createStationGrid(int nbLine, int begin, int end) {
		Line line = model.getLine(nbLine);
		JPanel stationPanel = new JPanel(new GridBagLayout());
		stationPanel.setPreferredSize(new Dimension(400, 390));
		GridBagConstraints gbc=new GridBagConstraints();

		stationPanel.setBorder(BorderFactory.createTitledBorder("Waiting time of Stations"));

		for(int i=begin; i<end; i++) {

			gbc.gridwidth=50;
			gbc.fill=GridBagConstraints.HORIZONTAL;
			gbc.weightx=1f;
			gbc.weighty=1f;

			final Station station = model.getStation(line, i);
			JLabel stationLabel = new JLabel(station.getName());
			stationLabel.setText(station.getName());
			stationLabel.setPreferredSize(new Dimension(180, 20));
			stationPanel.add(stationLabel, gbc);

			gbc.gridwidth=GridBagConstraints.REMAINDER;
			gbc.fill=GridBagConstraints.NONE;
			gbc.weightx=1f;
			gbc.weighty=1f;

			final SpinnerNumberModel spinnerWaitingTimeModel = new SpinnerNumberModel(model.getWaitingTime(station), 0, 999, 1);
			model.addStationListener(new StationAdapter() {
				@Override
				public void stationChange(StationEvent event) {
					if(StationEvent.CHANGED_WAITING == event.getEventType()) {
						if(station.equals(event.getSource())) {
							spinnerWaitingTimeModel.setValue(model.getWaitingTime(station));
						}
					}
				}
			});
			final JSpinner spinner = new JSpinner(spinnerWaitingTimeModel);
			spinner.setPreferredSize(new Dimension(40,20));
			stationPanel.add(spinner, gbc);
			mapStationSpinner.put(station, spinner);
			
		}

		return stationPanel;
	}

	/**
	 * Creates the number of trains panel.
	 * @param i the index of the line in the model.
	 * @return a JPanel which contains the numberOf train of the line.
	 */
	private JPanel createNumberTrainsPanel(int i) {
		JPanel numberTrainsPanel = new JPanel();
		numberTrainsPanel.setPreferredSize(new Dimension(500, 40));
		final Line line = model.getLine(i);
		final SpinnerNumberModel spinnerLineModel = new SpinnerNumberModel(model.getCountTrain(line), 0, model.getCountStation(line), 1);
		final JSpinner spinner = new JSpinner(spinnerLineModel);
		model.addTrainListener(new TrainListener() {
			@Override
			public void trainChange(TrainEvent event) {
				if(event.getEventType() == TrainEvent.TRAIN_ADDED || event.getEventType() == TrainEvent.TRAIN_REMOVE) {
					spinnerLineModel.setValue(model.getCountTrain(line));
				}
			}
		});
		spinner.setPreferredSize(new Dimension(40,20));

		numberTrainsPanel.add(new JLabel("Number of trains "));
		numberTrainsPanel.add(spinner);
		mapLineSpinner.put(line, spinner);
		return numberTrainsPanel;
	}

	/**
	 * Creates a tab for the Line on the index i.
	 * @param i the index of the line in the model.
	 * @return the panel of the configuration for the line on the index i.
	 */
	private JPanel createTab(int i) {
		JPanel panel = new JPanel();
		panel.setLayout(new GridBagLayout());
		panel.setPreferredSize(new Dimension(600, 450));

		//panel of number of train
		GridBagConstraints gbc=new GridBagConstraints();
		gbc.gridwidth=GridBagConstraints.REMAINDER;
		gbc.fill=GridBagConstraints.BOTH;
		panel.add(createNumberTrainsPanel(i),gbc);

		gbc.gridwidth=1;
		gbc.fill=GridBagConstraints.BOTH;
		gbc.weightx=1f;
		gbc.weighty=1f;

		Line line = model.getLine(i);

		panel.add(createStationGrid(i, 0, (model.getCountStation(line)/2) + 1), gbc);
		panel.add(createStationGrid(i, (model.getCountStation(line)/2) + 1, (model.getCountStation(line))), gbc);
		return panel;
	}

	/**
	 * Sets the current selected tab depends the index in parameter.
	 * @param index the index of the line in the model.
	 */
	public void setSelectedTab(int index) {
		tabpane.setSelectedIndex(index);
	}

	/**
	 * Initializes the components in the windows.
	 */
	private void init() {
		p.setPreferredSize(new Dimension(680, 480));
		tabpane.setName("Informations ");
		for(int i=0; i<model.getCountLine(); i++) {
			tabpane.add("Line " + (i+1), createTab(i));
		}
		p.add(tabpane);
		add(p);

		JPanel downPanel = new JPanel();
		JButton buttonOk = new JButton("OK");
		buttonOk.addActionListener(buttonOkListener());


		downPanel.add(buttonOk);

		JButton buttonCancel = new JButton("annuler");
		buttonCancel.addActionListener(dialogListner);
		downPanel.add(buttonCancel);
		add(downPanel,BorderLayout.SOUTH);
	}


	/**
	 * {@link ActionListener} for the button ok.
	 * @return a {@link ActionListener} for the butotn ok in this window.
	 */
	private ActionListener buttonOkListener() {
		return new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					/*** set number of train of all lines *****/
					for(Entry<Line, JSpinner> entry : mapLineSpinner.entrySet()) {
						Line line = entry.getKey();
						JSpinner spinner = entry.getValue();
						spinner.commitEdit();
						int nbTrains = (Integer) spinner.getValue();
						model.addTrains(line, nbTrains);
						
					}
					
					/*** set waiting time of all stations *****/
					for(Entry<Station, JSpinner> entry : mapStationSpinner.entrySet()) {
						Station station = entry.getKey();
						JSpinner spinner = entry.getValue();
						spinner.commitEdit();
						int time = (Integer) spinner.getValue();
						model.setWaitingTime(station, time);
					}
					
				} catch (ParseException e1) {
					e1.printStackTrace();
				}
				model.selectedLine(model.getLine(tabpane.getSelectedIndex()));
				dispose();
			}
		};
	}


	@Override
	public void start() {
		setLocationRelativeTo(getOwner());
		setVisible(true);
	}

}


